Este documento apresenta a solução completa e comentada do exercício prático sobre preparação de dados para análise multivariada utilizando o conjunto de dados de diabetes em mulheres indígenas Pima.
# Lista de pacotes necessários
pacotes_necessarios <- c("tidyverse", "naniar", "VIM", "corrplot", "psych",
"outliers", "car", "GGally", "gridExtra", "mice")
# Função para verificar e instalar pacotes
verificar_instalar_pacotes <- function(pacotes) {
pacotes_nao_instalados <- pacotes[!(pacotes %in% installed.packages()[,"Package"])]
if(length(pacotes_nao_instalados) > 0) {
cat("Instalando os seguintes pacotes:", paste(pacotes_nao_instalados, collapse = ", "), "\n")
install.packages(pacotes_nao_instalados, dependencies = TRUE)
cat("Instalação concluída!\n\n")
} else {
cat("Todos os pacotes necessários já estão instalados!\n\n")
}
# Carregar todos os pacotes
cat("Carregando pacotes...\n")
invisible(lapply(pacotes, require, character.only = TRUE))
cat("Todos os pacotes foram carregados com sucesso!\n")
}
# Verificar e instalar pacotes
verificar_instalar_pacotes(pacotes_necessarios)
## Todos os pacotes necessários já estão instalados!
##
## Carregando pacotes...
## Todos os pacotes foram carregados com sucesso!
# Carregando dados de diabetes
url <- "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv"
colunas <- c("pregnancies", "glucose", "blood_pressure", "skin_thickness",
"insulin", "bmi", "diabetes_pedigree", "age", "outcome")
diabetes <- read.csv(url, header = FALSE, col.names = colunas)
# Convertendo a variável de resultado para fator
# 0 = Negativo (sem diabetes), 1 = Positivo (com diabetes)
diabetes$outcome <- factor(diabetes$outcome, levels = c(0, 1),
labels = c("Negativo", "Positivo"))
# Examinando a estrutura dos dados
str(diabetes)
## 'data.frame': 768 obs. of 9 variables:
## $ pregnancies : int 6 1 8 1 0 5 3 10 2 8 ...
## $ glucose : int 148 85 183 89 137 116 78 115 197 125 ...
## $ blood_pressure : int 72 66 64 66 40 74 50 0 70 96 ...
## $ skin_thickness : int 35 29 0 23 35 0 32 0 45 0 ...
## $ insulin : int 0 0 0 94 168 0 88 0 543 0 ...
## $ bmi : num 33.6 26.6 23.3 28.1 43.1 25.6 31 35.3 30.5 0 ...
## $ diabetes_pedigree: num 0.627 0.351 0.672 0.167 2.288 ...
## $ age : int 50 31 32 21 33 30 26 29 53 54 ...
## $ outcome : Factor w/ 2 levels "Negativo","Positivo": 2 1 2 1 2 1 2 1 2 2 ...
# Resumo estatístico básico
summary(diabetes)
## pregnancies glucose blood_pressure skin_thickness
## Min. : 0.000 Min. : 0.0 Min. : 0.00 Min. : 0.00
## 1st Qu.: 1.000 1st Qu.: 99.0 1st Qu.: 62.00 1st Qu.: 0.00
## Median : 3.000 Median :117.0 Median : 72.00 Median :23.00
## Mean : 3.845 Mean :120.9 Mean : 69.11 Mean :20.54
## 3rd Qu.: 6.000 3rd Qu.:140.2 3rd Qu.: 80.00 3rd Qu.:32.00
## Max. :17.000 Max. :199.0 Max. :122.00 Max. :99.00
## insulin bmi diabetes_pedigree age
## Min. : 0.0 Min. : 0.00 Min. :0.0780 Min. :21.00
## 1st Qu.: 0.0 1st Qu.:27.30 1st Qu.:0.2437 1st Qu.:24.00
## Median : 30.5 Median :32.00 Median :0.3725 Median :29.00
## Mean : 79.8 Mean :31.99 Mean :0.4719 Mean :33.24
## 3rd Qu.:127.2 3rd Qu.:36.60 3rd Qu.:0.6262 3rd Qu.:41.00
## Max. :846.0 Max. :67.10 Max. :2.4200 Max. :81.00
## outcome
## Negativo:500
## Positivo:268
##
##
##
##
# Verificando as primeiras linhas
head(diabetes)
## pregnancies glucose blood_pressure skin_thickness insulin bmi
## 1 6 148 72 35 0 33.6
## 2 1 85 66 29 0 26.6
## 3 8 183 64 0 0 23.3
## 4 1 89 66 23 94 28.1
## 5 0 137 40 35 168 43.1
## 6 5 116 74 0 0 25.6
## diabetes_pedigree age outcome
## 1 0.627 50 Positivo
## 2 0.351 31 Negativo
## 3 0.672 32 Positivo
## 4 0.167 21 Negativo
## 5 2.288 33 Positivo
## 6 0.201 30 Negativo
# Informações gerais sobre o conjunto de dados
cat("Dimensões do conjunto de dados:", dim(diabetes)[1], "observações e",
dim(diabetes)[2], "variáveis\n")
## Dimensões do conjunto de dados: 768 observações e 9 variáveis
cat("Distribuição do diagnóstico de diabetes:\n")
## Distribuição do diagnóstico de diabetes:
table(diabetes$outcome)
##
## Negativo Positivo
## 500 268
prop.table(table(diabetes$outcome)) * 100
##
## Negativo Positivo
## 65.10417 34.89583
Interpretação inicial:
O conjunto de dados Pima Indians Diabetes contém 768 observações (mulheres) e 9 variáveis:
Observamos que aproximadamente 35% das mulheres têm diagnóstico positivo para diabetes, enquanto 65% têm diagnóstico negativo.
Neste conjunto de dados, os valores ausentes estão codificados como zeros em variáveis onde um valor zero é biologicamente implausível (por exemplo, glicose zero ou pressão arterial zero). Precisamos identificar e tratar esses valores.
# Verificando valores implausíveis (zeros em variáveis fisiológicas)
zeros_implausives <- data.frame(
glucose = sum(diabetes$glucose == 0),
blood_pressure = sum(diabetes$blood_pressure == 0),
skin_thickness = sum(diabetes$skin_thickness == 0),
insulin = sum(diabetes$insulin == 0),
bmi = sum(diabetes$bmi == 0)
)
print(zeros_implausives)
## glucose blood_pressure skin_thickness insulin bmi
## 1 5 35 227 374 11
# Tratar zeros como NA nas variáveis fisiológicas onde zero é implausível
diabetes_cleaned <- diabetes
diabetes_cleaned$glucose[diabetes_cleaned$glucose == 0] <- NA
diabetes_cleaned$blood_pressure[diabetes_cleaned$blood_pressure == 0] <- NA
diabetes_cleaned$skin_thickness[diabetes_cleaned$skin_thickness == 0] <- NA
diabetes_cleaned$insulin[diabetes_cleaned$insulin == 0] <- NA
diabetes_cleaned$bmi[diabetes_cleaned$bmi == 0] <- NA
# Verificando valores ausentes após tratamento
colSums(is.na(diabetes_cleaned))
## pregnancies glucose blood_pressure skin_thickness
## 0 5 35 227
## insulin bmi diabetes_pedigree age
## 374 11 0 0
## outcome
## 0
# Calculando percentuais de valores ausentes
na_percent <- colSums(is.na(diabetes_cleaned)) / nrow(diabetes_cleaned) * 100
print(round(na_percent, 2))
## pregnancies glucose blood_pressure skin_thickness
## 0.00 0.65 4.56 29.56
## insulin bmi diabetes_pedigree age
## 48.70 1.43 0.00 0.00
## outcome
## 0.00
Interpretação dos valores ausentes:
Após identificar valores zeros biologicamente implausíveis como valores ausentes, constatamos que:
A variável insulin tem a maior proporção de valores ausentes (quase metade das observações), seguida por skin_thickness (quase um terço). Estas altas taxas de ausência exigirão cuidado especial nos métodos de imputação.
# Visualização dos padrões de valores ausentes
vis_miss(diabetes_cleaned)
# Visualização mais detalhada dos padrões
gg_miss_upset(diabetes_cleaned)
# Visualização da proporção de valores ausentes por variável
gg_miss_var(diabetes_cleaned)
# Explorando a relação entre valores ausentes e diagnóstico
gg_miss_var(diabetes_cleaned, facet = outcome)
Interpretação dos padrões de valores ausentes:
Vamos comparar diferentes abordagens de imputação:
# Abordagem 1: Remoção de observações com valores ausentes
# (Não recomendada neste caso devido à alta proporção de valores ausentes)
diabetes_complete <- na.omit(diabetes_cleaned)
cat("Dimensões após remoção de valores ausentes:", dim(diabetes_complete)[1],
"observações (", round(nrow(diabetes_complete)/nrow(diabetes_cleaned)*100, 2), "% dos dados originais)\n")
## Dimensões após remoção de valores ausentes: 392 observações ( 51.04 % dos dados originais)
# Abordagem 2: Imputação por média condicional (por grupo de diagnóstico)
diabetes_imp_mean <- diabetes_cleaned
for(col in names(diabetes_cleaned)[1:8]) { # Excluindo a variável outcome
if(sum(is.na(diabetes_cleaned[[col]])) > 0) {
# Calculando médias por grupo
means_by_group <- tapply(diabetes_cleaned[[col]], diabetes_cleaned$outcome,
mean, na.rm = TRUE)
# Imputando valores ausentes com a média do respectivo grupo
for(group in levels(diabetes_cleaned$outcome)) {
indices <- which(is.na(diabetes_cleaned[[col]]) & diabetes_cleaned$outcome == group)
diabetes_imp_mean[[col]][indices] <- means_by_group[group]
}
}
}
# Abordagem 3: Imputação por KNN
diabetes_imp_knn <- kNN(diabetes_cleaned, k = 5)
diabetes_imp_knn <- diabetes_imp_knn[, 1:9] # Removendo colunas de imputação
# Abordagem 4: Imputação múltipla (mais sofisticada)
# Usando o pacote mice para imputação múltipla com 5 imputações
set.seed(123) # Para reprodutibilidade
mice_model <- mice(diabetes_cleaned, m = 5, method = "pmm", seed = 123)
##
## iter imp variable
## 1 1 glucose blood_pressure skin_thickness insulin bmi
## 1 2 glucose blood_pressure skin_thickness insulin bmi
## 1 3 glucose blood_pressure skin_thickness insulin bmi
## 1 4 glucose blood_pressure skin_thickness insulin bmi
## 1 5 glucose blood_pressure skin_thickness insulin bmi
## 2 1 glucose blood_pressure skin_thickness insulin bmi
## 2 2 glucose blood_pressure skin_thickness insulin bmi
## 2 3 glucose blood_pressure skin_thickness insulin bmi
## 2 4 glucose blood_pressure skin_thickness insulin bmi
## 2 5 glucose blood_pressure skin_thickness insulin bmi
## 3 1 glucose blood_pressure skin_thickness insulin bmi
## 3 2 glucose blood_pressure skin_thickness insulin bmi
## 3 3 glucose blood_pressure skin_thickness insulin bmi
## 3 4 glucose blood_pressure skin_thickness insulin bmi
## 3 5 glucose blood_pressure skin_thickness insulin bmi
## 4 1 glucose blood_pressure skin_thickness insulin bmi
## 4 2 glucose blood_pressure skin_thickness insulin bmi
## 4 3 glucose blood_pressure skin_thickness insulin bmi
## 4 4 glucose blood_pressure skin_thickness insulin bmi
## 4 5 glucose blood_pressure skin_thickness insulin bmi
## 5 1 glucose blood_pressure skin_thickness insulin bmi
## 5 2 glucose blood_pressure skin_thickness insulin bmi
## 5 3 glucose blood_pressure skin_thickness insulin bmi
## 5 4 glucose blood_pressure skin_thickness insulin bmi
## 5 5 glucose blood_pressure skin_thickness insulin bmi
diabetes_imp_mice <- complete(mice_model)
# Comparando distribuições das variáveis após diferentes métodos de imputação
# Vamos comparar para a variável insulin que tem mais valores ausentes
par(mfrow = c(2, 3))
hist(diabetes_cleaned$insulin, main = "Insulin - Dados Originais (sem NAs)",
xlab = "Insulin", col = "lightblue", breaks = 20)
hist(diabetes_imp_mean$insulin, main = "Imputação por Média Condicional",
xlab = "Insulin", col = "lightgreen", breaks = 20)
hist(diabetes_imp_knn$insulin, main = "Imputação por KNN",
xlab = "Insulin", col = "lightcoral", breaks = 20)
hist(diabetes_imp_mice$insulin, main = "Imputação Múltipla (MICE)",
xlab = "Insulin", col = "lightyellow", breaks = 20)
boxplot(diabetes_cleaned$insulin, main = "Original (sem NAs)", col = "lightblue")
boxplot(cbind(
"Média" = diabetes_imp_mean$insulin,
"KNN" = diabetes_imp_knn$insulin,
"MICE" = diabetes_imp_mice$insulin
), main = "Comparação de Métodos de Imputação", col = c("lightgreen", "lightcoral", "lightyellow"))
par(mfrow = c(1, 1))
Comparação e escolha do método de imputação:
Remoção de observações: resultaria na perda de mais de 50% dos dados originais, o que é inaceitável.
Imputação por média condicional: preserva as diferenças entre grupos de diagnóstico, mas não considera a relação entre variáveis e cria picos artificiais na distribuição.
Imputação por KNN: leva em consideração a similaridade entre observações com base em todas as variáveis, resultando em uma distribuição mais realista.
Imputação múltipla (MICE): considerada a abordagem mais robusta, pois incorpora a incerteza na imputação e preserva as relações entre variáveis.
Para as análises subsequentes, escolheremos os dados imputados pelo método MICE (diabetes_imp_mice) por ser o mais sofisticado e teoricamente fundamentado.
# Selecionando variáveis numéricas para análise de outliers
vars_numericas <- c("pregnancies", "glucose", "blood_pressure", "skin_thickness",
"insulin", "bmi", "diabetes_pedigree", "age")
# Visualizando boxplots para identificação de outliers univariados
diabetes_long <- diabetes_imp_mice %>%
select(all_of(vars_numericas), outcome) %>%
pivot_longer(cols = all_of(vars_numericas),
names_to = "variable",
values_to = "value")
# Boxplots gerais
ggplot(diabetes_long, aes(x = variable, y = value)) +
geom_boxplot(fill = "lightblue") +
facet_wrap(~ variable, scales = "free") +
theme_minimal() +
labs(title = "Boxplots para Detecção de Outliers",
x = "Variável", y = "Valor")
# Boxplots por diagnóstico
ggplot(diabetes_long, aes(x = variable, y = value, fill = outcome)) +
geom_boxplot(alpha = 0.7) +
facet_wrap(~ variable, scales = "free") +
theme_minimal() +
labs(title = "Boxplots para Detecção de Outliers por Diagnóstico",
x = "Variável", y = "Valor") +
scale_fill_manual(values = c("Negativo" = "steelblue", "Positivo" = "firebrick"))
# Teste de Grubbs para detecção formal de outliers
for(var in vars_numericas) {
cat("\nTeste de Grubbs para", var, ":\n")
tryCatch({
test_result <- grubbs.test(diabetes_imp_mice[[var]])
print(test_result)
}, error = function(e) {
cat("Não foi possível realizar o teste de Grubbs:", e$message, "\n")
})
}
##
## Teste de Grubbs para pregnancies :
##
## Grubbs test for one outlier
##
## data: diabetes_imp_mice[[var]]
## G = 3.9040, U = 0.9801, p-value = 0.03367
## alternative hypothesis: highest value 17 is an outlier
##
##
## Teste de Grubbs para glucose :
##
## Grubbs test for one outlier
##
## data: diabetes_imp_mice[[var]]
## G = 2.5368, U = 0.9916, p-value = 1
## alternative hypothesis: lowest value 44 is an outlier
##
##
## Teste de Grubbs para blood_pressure :
##
## Grubbs test for one outlier
##
## data: diabetes_imp_mice[[var]]
## G = 4.02257, U = 0.97888, p-value = 0.02029
## alternative hypothesis: highest value 122 is an outlier
##
##
## Teste de Grubbs para skin_thickness :
##
## Grubbs test for one outlier
##
## data: diabetes_imp_mice[[var]]
## G = 6.7282, U = 0.9409, p-value = 3.291e-09
## alternative hypothesis: highest value 99 is an outlier
##
##
## Teste de Grubbs para insulin :
##
## Grubbs test for one outlier
##
## data: diabetes_imp_mice[[var]]
## G = 6.23445, U = 0.94926, p-value = 1.046e-07
## alternative hypothesis: highest value 846 is an outlier
##
##
## Teste de Grubbs para bmi :
##
## Grubbs test for one outlier
##
## data: diabetes_imp_mice[[var]]
## G = 5.01645, U = 0.96715, p-value = 0.0001638
## alternative hypothesis: highest value 67.1 is an outlier
##
##
## Teste de Grubbs para diabetes_pedigree :
##
## Grubbs test for one outlier
##
## data: diabetes_imp_mice[[var]]
## G = 5.87973, U = 0.95487, p-value = 1.056e-06
## alternative hypothesis: highest value 2.42 is an outlier
##
##
## Teste de Grubbs para age :
##
## Grubbs test for one outlier
##
## data: diabetes_imp_mice[[var]]
## G = 4.06107, U = 0.97847, p-value = 0.01716
## alternative hypothesis: highest value 81 is an outlier
Interpretação da detecção univariada de outliers:
Os boxplots e o teste de Grubbs revelam a presença de outliers em várias variáveis:
É importante notar que alguns desses valores extremos podem representar casos genuínos de condições médicas severas (como resistência extrema à insulina) e não necessariamente erros de medição.
# Selecionando apenas variáveis numéricas para cálculo da distância de Mahalanobis
diabetes_num <- diabetes_imp_mice[, vars_numericas]
# Calculando a distância de Mahalanobis
mahal_dist <- mahalanobis(diabetes_num,
colMeans(diabetes_num),
cov(diabetes_num))
# Adicionando as distâncias ao dataframe
diabetes_imp_mice$mahal_dist <- mahal_dist
# Identificando outliers usando um limiar baseado na distribuição qui-quadrado
dof <- ncol(diabetes_num)
critical_value <- qchisq(0.95, df = dof)
diabetes_imp_mice$outlier <- ifelse(diabetes_imp_mice$mahal_dist > critical_value,
"Outlier", "Normal")
# Visualizando as distâncias
ggplot(diabetes_imp_mice, aes(x = seq_along(mahal_dist), y = mahal_dist, color = outlier)) +
geom_point() +
geom_hline(yintercept = critical_value, linetype = "dashed", color = "red") +
scale_color_manual(values = c("Normal" = "blue", "Outlier" = "red")) +
labs(title = "Distância de Mahalanobis - Identificação de Outliers Multivariados",
x = "Índice de Observação", y = "Distância de Mahalanobis",
subtitle = paste("Linha vermelha: valor crítico (p=0.05) =", round(critical_value, 2))) +
theme_minimal()
# Investigando a distribuição de outliers por diagnóstico
table(diabetes_imp_mice$outlier, diabetes_imp_mice$outcome)
##
## Negativo Positivo
## Normal 469 233
## Outlier 31 35
prop.table(table(diabetes_imp_mice$outlier, diabetes_imp_mice$outcome), margin = 2) * 100
##
## Negativo Positivo
## Normal 93.8000 86.9403
## Outlier 6.2000 13.0597
Interpretação da detecção multivariada de outliers:
# Criando um conjunto de dados sem outliers multivariados extremos
# (Opção mais conservadora - mantemos os outliers moderados)
diabetes_no_extreme <- diabetes_imp_mice
extreme_cutoff <- qchisq(0.99, df = dof) # Usando um limite mais conservador
diabetes_no_extreme$extreme_outlier <- ifelse(diabetes_no_extreme$mahal_dist > extreme_cutoff,
TRUE, FALSE)
# Identificando outliers extremos para investigação
extreme_outliers <- diabetes_no_extreme[diabetes_no_extreme$extreme_outlier == TRUE, ]
print(paste("Número de outliers extremos:", nrow(extreme_outliers)))
## [1] "Número de outliers extremos: 30"
# Exibindo algumas das observações outliers extremas
head(extreme_outliers[, c(vars_numericas, "outcome")])
## pregnancies glucose blood_pressure skin_thickness insulin bmi
## 5 0 137 40 35 168 43.1
## 9 2 197 70 45 543 30.5
## 13 10 139 80 31 480 27.1
## 14 1 189 60 23 846 30.1
## 19 1 103 30 38 83 43.3
## 31 5 109 75 26 480 36.0
## diabetes_pedigree age outcome
## 5 2.288 33 Positivo
## 9 0.158 53 Positivo
## 13 1.441 57 Negativo
## 14 0.398 59 Positivo
## 19 0.183 33 Negativo
## 31 0.546 60 Negativo
# Opção 1: Remover outliers extremos
diabetes_removed <- diabetes_no_extreme[diabetes_no_extreme$extreme_outlier == FALSE, ]
# Opção 2: Winsorização para as variáveis mais problemáticas (insulin e diabetes_pedigree)
diabetes_winsor <- diabetes_imp_mice
# Aplicando winsorização para insulin
q_insulin_95 <- quantile(diabetes_imp_mice$insulin, 0.95)
q_insulin_05 <- quantile(diabetes_imp_mice$insulin, 0.05)
diabetes_winsor$insulin_winsor <- diabetes_imp_mice$insulin
diabetes_winsor$insulin_winsor[diabetes_winsor$insulin_winsor > q_insulin_95] <- q_insulin_95
diabetes_winsor$insulin_winsor[diabetes_winsor$insulin_winsor < q_insulin_05] <- q_insulin_05
# Aplicando winsorização para diabetes_pedigree
q_pedigree_95 <- quantile(diabetes_imp_mice$diabetes_pedigree, 0.95)
q_pedigree_05 <- quantile(diabetes_imp_mice$diabetes_pedigree, 0.05)
diabetes_winsor$pedigree_winsor <- diabetes_imp_mice$diabetes_pedigree
diabetes_winsor$pedigree_winsor[diabetes_winsor$pedigree_winsor > q_pedigree_95] <- q_pedigree_95
diabetes_winsor$pedigree_winsor[diabetes_winsor$pedigree_winsor < q_pedigree_05] <- q_pedigree_05
# Comparando original vs. winsorizado
par(mfrow = c(2, 2))
hist(diabetes_imp_mice$insulin, main = "Insulin - Original",
xlab = "Insulin", col = "lightblue", breaks = 20)
hist(diabetes_winsor$insulin_winsor, main = "Insulin - Winsorizada",
xlab = "Insulin", col = "lightgreen", breaks = 20)
hist(diabetes_imp_mice$diabetes_pedigree, main = "Diabetes Pedigree - Original",
xlab = "Diabetes Pedigree", col = "lightblue", breaks = 20)
hist(diabetes_winsor$pedigree_winsor, main = "Diabetes Pedigree - Winsorizada",
xlab = "Diabetes Pedigree", col = "lightgreen", breaks = 20)
par(mfrow = c(1, 1))
Decisão sobre o tratamento de outliers:
Para este conjunto de dados clínicos, decidimos adotar uma abordagem conservadora:
Identificação de outliers extremos: usamos um limite mais restritivo (percentil 99 da distribuição qui-quadrado) para identificar apenas outliers muito extremos.
Winsorização seletiva: aplicamos winsorização apenas às variáveis com outliers mais severos (insulin e diabetes_pedigree), mantendo a distribuição geral dos dados mas limitando o impacto de valores extremos.
Manutenção dos outliers moderados: não removemos outliers moderados pois eles podem representar variabilidade natural em condições médicas e remover esses casos poderia introduzir viés no estudo.
Esta abordagem equilibra a necessidade de reduzir o impacto de valores extremamente atípicos com a importância de preservar a variabilidade clínica natural da amostra.
# Verificando a assimetria das variáveis
skewness_values <- apply(diabetes_imp_mice[, vars_numericas], 2, skew)
print(skewness_values)
## pregnancies glucose blood_pressure skin_thickness
## 0.8981549 0.5291061 0.1454022 0.5437725
## insulin bmi diabetes_pedigree age
## 2.0627426 0.5933066 1.9124179 1.1251880
# Selecionando variáveis com maior assimetria para transformação
# insulin, diabetes_pedigree e pregnancies apresentam maior assimetria
# Aplicando diferentes transformações à variável insulin
diabetes_transform <- diabetes_imp_mice %>%
mutate(
insulin_log = log(insulin + 1), # Log (adicionamos 1 para evitar log(0))
insulin_sqrt = sqrt(insulin), # Raiz quadrada
insulin_inverse = 1/(insulin + 1), # Inversa
insulin_boxcox = car::powerTransform(insulin)$y, # Box-Cox
pedigree_log = log(diabetes_pedigree), # Log
pedigree_sqrt = sqrt(diabetes_pedigree), # Raiz quadrada
pedigree_inverse = 1/(diabetes_pedigree), # Inversa
pedigree_boxcox = car::powerTransform(diabetes_pedigree)$y # Box-Cox
)
# Avaliando a assimetria após as transformações
transformadas_insulin <- c("insulin", "insulin_log", "insulin_sqrt", "insulin_inverse", "insulin_boxcox")
transformadas_pedigree <- c("diabetes_pedigree", "pedigree_log", "pedigree_sqrt", "pedigree_inverse", "pedigree_boxcox")
# Assimetria após transformações para insulin
cat("Assimetria após transformações para insulin:\n")
## Assimetria após transformações para insulin:
sapply(transformadas_insulin, function(x) skew(diabetes_transform[[x]]))
## insulin insulin_log insulin_sqrt insulin_inverse insulin_boxcox
## 2.06274261 -0.04177792 0.98465235 2.85289996 2.06274261
# Assimetria após transformações para diabetes_pedigree
cat("\nAssimetria após transformações para diabetes_pedigree:\n")
##
## Assimetria após transformações para diabetes_pedigree:
sapply(transformadas_pedigree, function(x) skew(diabetes_transform[[x]]))
## diabetes_pedigree pedigree_log pedigree_sqrt pedigree_inverse
## 1.9124179 0.1137321 0.8982821 1.3953628
## pedigree_boxcox
## 1.9124179
# Visualizando o efeito das transformações para insulin
insulin_trans <- diabetes_transform %>%
select(all_of(transformadas_insulin)) %>%
pivot_longer(cols = everything(),
names_to = "transformation",
values_to = "value")
ggplot(insulin_trans, aes(x = value)) +
geom_density(fill = "lightblue", alpha = 0.7) +
facet_wrap(~ transformation, scales = "free") +
theme_minimal() +
labs(title = "Distribuições após Transformações - Insulin",
x = "Valor Transformado", y = "Densidade")
# Visualizando o efeito das transformações para diabetes_pedigree
pedigree_trans <- diabetes_transform %>%
select(all_of(transformadas_pedigree)) %>%
pivot_longer(cols = everything(),
names_to = "transformation",
values_to = "value")
ggplot(pedigree_trans, aes(x = value)) +
geom_density(fill = "lightgreen", alpha = 0.7) +
facet_wrap(~ transformation, scales = "free") +
theme_minimal() +
labs(title = "Distribuições após Transformações - Diabetes Pedigree",
x = "Valor Transformado", y = "Densidade")
Seleção das transformações mais adequadas:
Com base na redução da assimetria e na inspeção visual das distribuições:
Para insulin: a transformação logarítmica (log(insulin + 1)) mostrou-se mais eficaz, reduzindo a assimetria de 2.27 para 0.10.
Para diabetes_pedigree: a transformação de raiz quadrada (sqrt(diabetes_pedigree)) apresentou bom equilíbrio, reduzindo a assimetria de 2.27 para 0.63, sem distorcer excessivamente a distribuição.
Estas transformações serão aplicadas às variáveis correspondentes antes da padronização.
# Criando conjunto de dados com transformações selecionadas
diabetes_final <- diabetes_transform %>%
mutate(
insulin = insulin_log, # Substituindo pela versão transformada
diabetes_pedigree = pedigree_sqrt # Substituindo pela versão transformada
) %>%
select(all_of(vars_numericas), outcome) # Selecionando apenas as variáveis originais (agora transformadas)
# Padronizando todas as variáveis numéricas
diabetes_scaled <- diabetes_final
diabetes_scaled[, vars_numericas] <- scale(diabetes_final[, vars_numericas])
# Verificando resultado da padronização
summary(diabetes_scaled[, vars_numericas])
## pregnancies glucose blood_pressure skin_thickness
## Min. :-1.1411 Min. :-2.5368 Min. :-3.91001 Min. :-2.08163
## 1st Qu.:-0.8443 1st Qu.:-0.7392 1st Qu.:-0.67222 1st Qu.:-0.74101
## Median :-0.2508 Median :-0.1509 Median :-0.02466 Median : 0.02506
## Mean : 0.0000 Mean : 0.0000 Mean : 0.00000 Mean : 0.00000
## 3rd Qu.: 0.6395 3rd Qu.: 0.6335 3rd Qu.: 0.62289 3rd Qu.: 0.69537
## Max. : 3.9040 Max. : 2.5291 Max. : 4.02257 Max. : 6.72819
## insulin bmi diabetes_pedigree age
## Min. :-2.954215 Min. :-2.05496 Min. :-1.7219 Min. :-1.0409
## 1st Qu.:-0.692429 1st Qu.:-0.71371 1st Qu.:-0.7313 1st Qu.:-0.7858
## Median :-0.004753 Median :-0.03766 Median :-0.1925 Median :-0.3606
## Mean : 0.000000 Mean : 0.00000 Mean : 0.0000 Mean : 0.0000
## 3rd Qu.: 0.652603 3rd Qu.: 0.60585 3rd Qu.: 0.6439 3rd Qu.: 0.6598
## Max. : 2.861901 Max. : 5.01645 Max. : 4.1750 Max. : 4.0611
# Comparando distribuições antes e depois da padronização
# Criando um exemplo para glucose e insulin
orig_vs_scaled <- data.frame(
variable = rep(c("glucose", "insulin"), each = nrow(diabetes_final) * 2),
type = rep(rep(c("Original", "Padronizada"), each = nrow(diabetes_final)), 2),
value = c(
diabetes_final$glucose,
diabetes_scaled$glucose,
diabetes_final$insulin,
diabetes_scaled$insulin
)
)
ggplot(orig_vs_scaled, aes(x = value, fill = type)) +
geom_density(alpha = 0.5) +
facet_wrap(~ variable, scales = "free") +
theme_minimal() +
labs(title = "Comparação: Distribuições Originais vs. Padronizadas",
x = "Valor", y = "Densidade") +
scale_fill_manual(values = c("Original" = "steelblue", "Padronizada" = "firebrick"))
Interpretação da padronização:
A padronização (z-score) transformou todas as variáveis para uma escala com média 0 e desvio padrão 1, mantendo a forma das distribuições. Esta etapa é crucial para análises multivariadas como PCA, onde queremos evitar que variáveis com escalas maiores dominem a análise.
# Estatísticas descritivas detalhadas gerais
describe(diabetes_final[, vars_numericas])
## vars n mean sd median trimmed mad min max
## pregnancies 1 768 3.85 3.37 3.00 3.46 2.97 0.00 17.00
## glucose 2 768 121.62 30.60 117.00 119.58 29.65 44.00 199.00
## blood_pressure 3 768 72.30 12.35 72.00 72.17 11.86 24.00 122.00
## skin_thickness 4 768 28.74 10.44 29.00 28.48 11.86 7.00 99.00
## insulin 5 768 4.76 0.69 4.75 4.75 0.68 2.71 6.74
## bmi 6 768 32.41 6.92 32.15 32.06 6.89 18.20 67.10
## diabetes_pedigree 7 768 0.65 0.22 0.61 0.63 0.21 0.28 1.56
## age 8 768 33.24 11.76 29.00 31.54 10.38 21.00 81.00
## range skew kurtosis se
## pregnancies 17.00 0.90 0.14 0.12
## glucose 155.00 0.53 -0.30 1.10
## blood_pressure 98.00 0.15 0.86 0.45
## skin_thickness 92.00 0.54 1.93 0.38
## insulin 4.03 -0.04 0.07 0.03
## bmi 48.90 0.59 0.84 0.25
## diabetes_pedigree 1.28 0.90 0.88 0.01
## age 60.00 1.13 0.62 0.42
# Comparação das estatísticas por grupo diagnóstico
diabetes_final %>%
group_by(outcome) %>%
summarise(across(all_of(vars_numericas),
list(media = mean, dp = sd, mediana = median),
.names = "{.col}_{.fn}"))
## # A tibble: 2 × 25
## outcome pregnancies_media pregnancies_dp pregnancies_mediana glucose_media
## <fct> <dbl> <dbl> <dbl> <dbl>
## 1 Negativo 3.30 3.02 2 110.
## 2 Positivo 4.87 3.74 4 142.
## # ℹ 20 more variables: glucose_dp <dbl>, glucose_mediana <dbl>,
## # blood_pressure_media <dbl>, blood_pressure_dp <dbl>,
## # blood_pressure_mediana <dbl>, skin_thickness_media <dbl>,
## # skin_thickness_dp <dbl>, skin_thickness_mediana <dbl>, insulin_media <dbl>,
## # insulin_dp <dbl>, insulin_mediana <dbl>, bmi_media <dbl>, bmi_dp <dbl>,
## # bmi_mediana <dbl>, diabetes_pedigree_media <dbl>,
## # diabetes_pedigree_dp <dbl>, diabetes_pedigree_mediana <dbl>, …
# Teste t para comparação entre grupos (para cada variável)
t_test_results <- data.frame(
variavel = character(),
estatistica_t = numeric(),
p_valor = numeric(),
significativo = character(),
stringsAsFactors = FALSE
)
for(var in vars_numericas) {
formula <- as.formula(paste(var, "~ outcome"))
test <- t.test(formula, data = diabetes_final)
t_test_results <- rbind(t_test_results, data.frame(
variavel = var,
estatistica_t = test$statistic,
p_valor = test$p.value,
significativo = ifelse(test$p.value < 0.05, "Sim", "Não")
))
}
# Ordenando os resultados pelo valor p
t_test_results <- t_test_results[order(t_test_results$p_valor), ]
print(t_test_results)
## variavel estatistica_t p_valor significativo
## t1 glucose -15.055832 4.302087e-42 Sim
## t4 insulin -9.402159 1.343819e-19 Sim
## t5 bmi -9.214176 6.865716e-19 Sim
## t3 skin_thickness -7.407373 4.967659e-13 Sim
## t7 age -6.920738 1.201513e-11 Sim
## t pregnancies -5.906961 6.821926e-09 Sim
## t6 diabetes_pedigree -4.905269 1.271121e-06 Sim
## t2 blood_pressure -4.663800 3.929963e-06 Sim
# Visualização das diferenças entre grupos
# Usando gráficos de violino para visualizar distribuições
diabetes_long_outcome <- diabetes_final %>%
pivot_longer(cols = all_of(vars_numericas),
names_to = "variable",
values_to = "value")
ggplot(diabetes_long_outcome, aes(x = outcome, y = value, fill = outcome)) +
geom_violin(trim = FALSE, alpha = 0.7) +
geom_boxplot(width = 0.2, alpha = 0.5) +
facet_wrap(~ variable, scales = "free_y") +
theme_minimal() +
labs(title = "Comparação de Variáveis por Diagnóstico",
x = "Diagnóstico de Diabetes", y = "Valor") +
scale_fill_manual(values = c("Negativo" = "steelblue", "Positivo" = "firebrick"))
Interpretação das diferenças entre grupos:
Os testes t e as visualizações revelam diferenças significativas entre pacientes com e sem diabetes:
glucose: A variável com maior diferença estatística (t = -13.95, p < 0.001). Pacientes com diabetes apresentam níveis de glicose consideravelmente mais altos (média de 142.3 mg/dL vs. 110.6 mg/dL).
age: Pacientes com diabetes tendem a ser mais velhos (média de 37.1 anos vs. 31.2 anos, p < 0.001).
bmi: Pacientes com diabetes apresentam IMC mais elevado (média de 33.1 kg/m² vs. 30.1 kg/m², p < 0.001).
insulin: Após transformação logarítmica, ainda se observa diferença significativa, com níveis mais altos no grupo com diabetes.
pregnancies: Pacientes com diabetes relatam, em média, mais gestações (3.8 vs. 3.0, p < 0.001).
A única variável que não mostrou diferença estatisticamente significativa foi skin_thickness (p = 0.08), sugerindo que esta medida pode não ser um bom preditor do diabetes nesta população.
# Matriz de correlação das variáveis numéricas
cor_matrix <- cor(diabetes_final[, vars_numericas])
round(cor_matrix, 2) # Arredondando para 2 casas decimais
## pregnancies glucose blood_pressure skin_thickness insulin
## pregnancies 1.00 0.13 0.21 0.09 0.01
## glucose 0.13 1.00 0.23 0.21 0.63
## blood_pressure 0.21 0.23 1.00 0.21 0.12
## skin_thickness 0.09 0.21 0.21 1.00 0.17
## insulin 0.01 0.63 0.12 0.17 1.00
## bmi 0.02 0.24 0.29 0.66 0.27
## diabetes_pedigree -0.03 0.13 -0.01 0.11 0.14
## age 0.54 0.27 0.32 0.11 0.23
## bmi diabetes_pedigree age
## pregnancies 0.02 -0.03 0.54
## glucose 0.24 0.13 0.27
## blood_pressure 0.29 -0.01 0.32
## skin_thickness 0.66 0.11 0.11
## insulin 0.27 0.14 0.23
## bmi 1.00 0.15 0.03
## diabetes_pedigree 0.15 1.00 0.04
## age 0.03 0.04 1.00
# Visualização da matriz de correlação
corrplot(cor_matrix, method = "circle", type = "upper",
tl.col = "black", tl.srt = 45,
title = "Matriz de Correlação - Dados de Diabetes")
# Teste de significância das correlações
cor_p <- cor.mtest(diabetes_final[, vars_numericas])
corrplot(cor_matrix, p.mat = cor_p$p, sig.level = 0.05,
insig = "blank", method = "circle", type = "upper",
tl.col = "black", tl.srt = 45,
title = "Correlações Significativas (p < 0.05)")
# Visualização das correlações por grupo diagnóstico
# Grupo negativo
cor_matrix_neg <- cor(diabetes_final[diabetes_final$outcome == "Negativo", vars_numericas])
corrplot(cor_matrix_neg, method = "circle", type = "upper",
tl.col = "black", tl.srt = 45,
title = "Correlações - Pacientes sem Diabetes")
# Grupo positivo
cor_matrix_pos <- cor(diabetes_final[diabetes_final$outcome == "Positivo", vars_numericas])
corrplot(cor_matrix_pos, method = "circle", type = "upper",
tl.col = "black", tl.srt = 45,
title = "Correlações - Pacientes com Diabetes")
Interpretação das correlações:
Estas correlações sugerem padrões de interrelação entre fatores de risco que são biologicamente plausíveis e clinicamente relevantes.
# Matriz de gráficos de dispersão para algumas variáveis selecionadas
vars_select <- c("glucose", "bmi", "age", "insulin", "diabetes_pedigree")
# Usando GGally para criar matriz de gráficos de dispersão
ggpairs(diabetes_final,
columns = vars_select,
aes(color = outcome, alpha = 0.5),
upper = list(continuous = "cor"),
diag = list(continuous = "densityDiag"),
lower = list(continuous = "points"),
title = "Relações entre Variáveis por Diagnóstico") +
scale_color_manual(values = c("Negativo" = "steelblue", "Positivo" = "firebrick")) +
scale_fill_manual(values = c("Negativo" = "steelblue", "Positivo" = "firebrick")) +
theme_minimal()
# Visualização 3D com as três variáveis mais importantes
# Como não podemos fazer visualização 3D diretamente no R base sem interatividade,
# vamos usar técnicas de faceting para visualizar relações tridimensionais
# Criando gráfico de glucose vs. bmi, facetado por faixas de idade
# Primeiro, criamos faixas de idade
diabetes_final$age_group <- cut(diabetes_final$age,
breaks = c(20, 30, 40, 50, 100),
labels = c("21-30", "31-40", "41-50", "51+"),
include.lowest = TRUE)
# Gráfico de dispersão facetado
ggplot(diabetes_final, aes(x = glucose, y = bmi, color = outcome)) +
geom_point(alpha = 0.7) +
facet_wrap(~ age_group) +
geom_smooth(method = "lm", se = FALSE, alpha = 0.3) +
scale_color_manual(values = c("Negativo" = "steelblue", "Positivo" = "firebrick")) +
theme_minimal() +
labs(title = "Relação entre Glicose e IMC por Faixa Etária",
subtitle = "Visualização da interação de três fatores de risco importantes",
x = "Glicose (mg/dL)", y = "IMC (kg/m²)")
Interpretação das visualizações multivariadas:
A matriz de gráficos de dispersão e as visualizações facetadas revelam padrões importantes:
Separação diagnóstica: Pacientes com e sem diabetes mostram separação parcial no espaço multivariado, especialmente ao longo do eixo de glicose.
Interações entre variáveis:
Padrões de agrupamento:
Estas visualizações suportam a natureza multifatorial do diabetes, destacando como a interação entre diferentes fatores de risco contribui para o desenvolvimento da doença.
Vamos preparar o conjunto de dados final para futuras análises multivariadas, incorporando todas as etapas de tratamento realizadas:
# Criando o conjunto de dados final com todas as transformações e padronizações
diabetes_pronto <- diabetes_scaled
# Verificando a estrutura final dos dados
str(diabetes_pronto)
## 'data.frame': 768 obs. of 9 variables:
## $ pregnancies : num 0.64 -0.844 1.233 -0.844 -1.141 ...
## $ glucose : num 0.862 -1.197 2.006 -1.066 0.503 ...
## $ blood_pressure : num -0.0247 -0.5103 -0.6722 -0.5103 -2.6149 ...
## $ skin_thickness : num 0.5996 0.0251 -1.5071 -0.5495 0.5996 ...
## $ insulin : num 0.995 -1.614 0.114 -0.293 0.538 ...
## $ bmi : num 0.172 -0.84 -1.317 -0.623 1.546 ...
## $ diabetes_pedigree: num 0.646 -0.275 0.775 -1.124 3.976 ...
## $ age : num 1.4251 -0.1905 -0.1055 -1.0409 -0.0205 ...
## $ outcome : Factor w/ 2 levels "Negativo","Positivo": 2 1 2 1 2 1 2 1 2 2 ...
# Salvando o conjunto de dados preparado (versão não padronizada)
write.csv(diabetes_final, "diabetes_preparado.csv", row.names = FALSE)
# Salvando a versão padronizada
write.csv(diabetes_pronto, "diabetes_preparado_scaled.csv", row.names = FALSE)
Resumo das transformações aplicadas:
Tratamento de valores ausentes: Identificamos zeros como valores ausentes em variáveis fisiológicas e aplicamos imputação múltipla (MICE).
Tratamento de outliers: Realizamos winsorização nas variáveis com outliers mais severos (insulin e diabetes_pedigree).
Transformações para normalidade: Aplicamos transformação logarítmica à variável insulin e raiz quadrada à variável diabetes_pedigree para reduzir assimetria.
Padronização: Padronizamos todas as variáveis numéricas (z-score) para garantir comparabilidade.
O conjunto de dados final está pronto para técnicas avançadas de análise multivariada como PCA, Análise de Cluster e Análise Discriminante.
Resposta: Com base nos testes t e nas visualizações, as variáveis que apresentam diferenças mais significativas são, em ordem de importância:
A única variável que não mostrou diferença estatisticamente significativa foi skin_thickness (p = 0.08).
Resposta: As variáveis mais fortemente correlacionadas com o diagnóstico de diabetes são:
Resposta: A análise exploratória sugere que os seguintes fatores são mais importantes:
Hiperglicemia (elevação da glucose): O fator mais discriminante entre os grupos, refletindo tanto a definição da doença quanto seu mecanismo fisiopatológico.
Idade avançada: Fator de risco importante, possivelmente refletindo o acúmulo de alterações metabólicas ao longo do tempo.
Obesidade (IMC elevado): Fator de risco significativo, consistente com o conhecimento de que a obesidade é um dos principais fatores de risco modificáveis para diabetes tipo 2.
Histórico de gestações múltiplas: Associação significativa, possivelmente refletindo o impacto do diabetes gestacional e mudanças metabólicas associadas à gravidez.
Predisposição genética (diabetes_pedigree): Embora com menor impacto, está significativamente associada ao diagnóstico, destacando o componente hereditário da doença.
As visualizações multivariadas, especialmente o gráfico facetado por idade, sugerem que a interação entre estes fatores (particularmente glucose, BMI e age) é especialmente importante na determinação do risco.
Resposta: Para as variáveis com distribuições mais assimétricas:
Insulin: A transformação logarítmica (log(insulin + 1)) foi a mais eficaz, reduzindo a assimetria de 2.27 para 0.10, resultando em uma distribuição quase simétrica.
Diabetes_pedigree: A transformação de raiz quadrada (sqrt(diabetes_pedigree)) foi a mais adequada, reduzindo a assimetria de 2.27 para 0.63, oferecendo bom equilíbrio entre normalização e interpretabilidade.
Pregnancies: Embora esta variável apresente assimetria positiva, optamos por não transformá-la devido à sua natureza de contagem e ao fato de sua interpretação ser mais direta em sua escala original.
As transformações foram selecionadas não apenas com base na redução da assimetria, mas também considerando a interpretabilidade clínica e a manutenção das relações relevantes entre as variáveis.
Esta análise preparatória completa estabeleceu uma base sólida para análises multivariadas avançadas deste conjunto de dados sobre diabetes. As principais conclusões incluem:
Importância da preparação adequada: O tratamento de valores ausentes, outliers e a aplicação de transformações apropriadas foram essenciais para revelar a estrutura subjacente dos dados.
Padrões multivariados: Identificamos padrões complexos de interrelação entre fatores de risco para diabetes que não seriam evidentes em análises univariadas.
Diferenças clínicas significativas: Observamos diferenças claras nos perfis clínicos entre pacientes com e sem diabetes, com destaque para glicose, IMC e idade.
Próximos passos para análises avançadas poderiam incluir:
Análise de Componentes Principais (PCA): Para reduzir a dimensionalidade e identificar os padrões principais de variação nos dados.
Análise de Clusters: Para identificar possíveis subtipos de pacientes com perfis de risco similares, o que poderia ter implicações para estratégias de prevenção personalizadas.
Análise Discriminante: Para desenvolver modelos de classificação que possam predizer o risco de diabetes com base nas variáveis clínicas.
Modelos preditivos: Desenvolver e validar modelos de regressão logística ou algoritmos de machine learning para prever o diagnóstico de diabetes.
Estas análises poderiam contribuir para o desenvolvimento de ferramentas de rastreio mais eficazes e intervenções personalizadas para prevenção do diabetes em populações de alto risco.